/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Domain;

import Domain.Player.*;
import java.io.Serializable;

/**
 *
 * @author sa11
 */
public class GameGrid implements Serializable{
    // Constants

    public static final int GRID_ROWS = 3, GRID_COLUMNS = 3;
    //The constant that is returned if a method such as addDisc fails.
    //public static final int FAILURE = -1;
    // Members
    private DomainController logicController;
    private Disc[][] grid = new Disc[GRID_ROWS][GRID_COLUMNS];
    private GameRules gameRules = new RulesTicTacToe(this);

    /**
     * Constructor.
     */
    public GameGrid(DomainController logicController) {
        resetGameGrid();
        this.logicController = logicController;
    }

    public DomainController getLogicController() {
        return logicController;
    }
    
    public GameGrid(){
        resetGameGrid();
    }
    
    /**
     * Returns true if the game is a tie, otherwise false.
     */
    public boolean isTie() {
        return gameRules.isTie();
    }

    /**
     * Returns the game rules instance
     */
    public GameRules getGameRules() {
        return gameRules;
    }

    /**
     * Resets the game grid
     */
    public void resetGameGrid() {
        for (int i = 0; i < GRID_ROWS; i++) {
            for (int j = 0; j < GRID_COLUMNS; j++) {
                grid[i][j] = Disc.NONE;
            }
        }
    }

    /**
     * Adds a disc to the grid. If succeeded the current row number is returned,
     * otherwise FAILURE.
     */
    public boolean addDisc(int row, int column, Disc discID) {
        if (grid[row][column] == Disc.NONE) {
            // grid[row][column] = logicController.getCurrentPlayer().getDiscID();
            grid[row][column] = discID;
            return true;
        }
        return false;
    }
    /*
     * for (int i = GRID_ROWS - 1; i >= 0; i--) { if (grid[i][column] ==
     * Disc.NONE) { grid[i][column] =
     * logicController.getCurrentPlayer().getDiscID(); return i; }
     *
     * }
     * return FAILURE;
     *
     */

    /**
     * Same as addDisc, but with a choice of disc.
     */
    public boolean setDisc(int row, int column, Disc disc) {
        if (grid[row][column] == Disc.NONE) {
            grid[row][column] = disc;
            return true;
        }
        return false;
    }

    /**
     * Returns true if the provided column is full
     */
    /*
     * public boolean isFull(int column) { return (grid[0][column] !=
     * Disc.NONE); }
     */
    /**
     * Returns the disc type of the winner
     */
    public Disc getWinner() {
        return gameRules.getWinner();
    }

    /**
     * Returns true if someone has won the game
     */
    public boolean hasWon() {
        return gameRules.hasWon();
    }
    
    /** Returns true if the provided column is full */
	public boolean isFull(int column) {
//		int i = 0;
//		while (i < GRID_ROWS && grid[i][column] != Disc.NONE) {
//			i++;
//		}
//		return !(i < GRID_ROWS);
		return (grid[0][column] != Disc.NONE);
	}
        
        /** Returns true if the provided column is full */
	public boolean isFull() {
            for(int i = 0; i < grid.length; i++){
                for(int j = 0; j < grid[0].length; j++){
                    if(grid[i][j] == Disc.NONE){
                        return false;
                    }
                }
            }
            return true;
	}

    /**
     * Returns true if the move row, column combination wins the game, otherwise
     * false.
     */
    public boolean winningMove(int row, int column) {
        return gameRules.hasWon(row, column);
    }

    /**
     * Returns whether or not the move is valid.
     */
    public boolean isValidMove(int column, int row) {
        return gameRules.isValidMove(column, row);
    }

    /**
     * Removes a disc at the specified row and column, if there are no discs
     * above it. (To be used by the computer when it tests different solutions
     * on its own gamegrid.)
     */
    public void removeDisc(int row, int col) {
        grid[row][col] = Disc.NONE;

    }

    /**
     * Removes the topmost disc in the specified column.
     */
    /*
     * public void removeDisc(int column) { int i; for (i = 0; (i < GRID_ROWS)
     * && (grid[i][column] == Disc.NONE); i++); if (i < GRID_ROWS) {
     * grid[i][column] = Disc.NONE; } }
     */
    /**
     * Copies the grid from another GameGrid. (Used by the computer when it
     * needs to create a copy of the current state to test different moves on
     * it.)
     */
    //BORDE LA INTE BEHÖVAS?
    public void copyFromGrid(GameGrid grid) {
        for (int i = 0; i < GRID_ROWS; i++) {
            for (int j = 0; j < GRID_COLUMNS; j++) {
                this.grid[i][j] = grid.getDisc(i, j);
            }
        }
    }

    /**
     * Returns a Disc object on the row, column combination on the grid
     */
    public Disc getDisc(int row, int column) {
        return grid[row][column];
    }

    /*
     * returns true if the gamegrid is empty
     */
    public boolean isEmpty() {
        for (int i = 0; i < GRID_ROWS; i++) {
            for (int j = 0; j < GRID_COLUMNS; j++) {
                if (grid[i][j] != Disc.NONE) {
                    return false;
                }
            }
        }
        return true;
    }

    /*
     * returns true if the the specified row contians no set Discs
     */
    //BORDE LA INTE BEHÖVAS?
    public boolean isRowEmpty(int row) {
        for (int i = GRID_COLUMNS - 1; i >= 0; i--) {
            if (grid[row][i] != Disc.NONE) {
                return false;
            }
        }
        return true;
    }

    /**
     * Setting disc at row and column in the gamegrid.
     */
    public void setDiscAt(int row, int column, Disc disc) {
        if (disc == Disc.NONE) {
            grid[row][column] = Disc.NONE;
        } else {
            grid[row][column] = (disc == Disc.ONE) ? Disc.ONE : Disc.TWO; // use this to make sure that it is the value and not the reference to an disc that is set
        }
    }

    /**
     * Setting reversed disc at row and column in the gamegrid.
     */
    //NÄR NYTTJASS DEN?
    public void setDiscReversedAt(int row, int column, Disc disc) {
        if (disc == Disc.NONE) {
            grid[row][column] = Disc.NONE;
        } else {
            grid[row][column] = disc == Disc.TWO ? Disc.ONE : Disc.TWO; // use this to make sure that it is the value and not the referens to an disc that is set
        }
    }

    /**
     * returns the gamegrid reversed(1->2, 2->1)
     */
    //NÄR NYTTJASS DEN?
    public GameGrid reversedGameGrid() {
        GameGrid temp = new GameGrid();

        for (int i = 0; i < GameGrid.GRID_ROWS; i++) {
            for (int j = 0; j < GameGrid.GRID_COLUMNS; j++) {
                temp.setDiscReversedAt(i, j, grid[i][j]);
            }
        }
        return temp;
    }

    /**
     * returns the grid as an string object
     */
    @Override
    public String toString() {
        String temp = "Grid: \n";
        for (int i = 0; i < GRID_ROWS; i++) {
            for (int j = 0; j < GRID_COLUMNS; j++) {
                temp += grid[i][j].ordinal() + " ";
            }
            temp += "\n";
        }
        return temp;
    }
    
    public static Square columnThatDiffer(GameGrid prev, GameGrid cur) {
	for (int i = GameGrid.GRID_ROWS - 1; i >= 0; i--) {
	    for (int j = GameGrid.GRID_COLUMNS - 1; j >= 0; j--) {
		if (prev.getDisc(i, j) != cur.getDisc(i, j)) {
                    Square tempSquare = new Square();
		    //System.out.println("column that differ " + j + " on grids " + prev.toString() + " and " + cur.toString());
                    tempSquare.setX(i);
                    tempSquare.setY(j);
		    return tempSquare;
		}
	    }
	}
        return null;
    }
}
